package com.xiangxiao.rpan.storage.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.xiangxiao.rpan.storage.dao.FilterConfigMapper;
import com.xiangxiao.rpan.storage.entity.FilterConfig;
import com.xiangxiao.rpan.storage.service.FilterConfigService;
import com.xiangxiao.rpan.storage.utils.PatternMatcherUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * @auther xiangxiao
 * @email 573768011@qq.com
 * @data 2023/11/16 20:50
 */
@Slf4j
@Service
public class FilterConfigServiceImpl implements FilterConfigService {
  @Resource
  private FilterConfigMapper filterConfigMapper;
  @Resource
  private SqlSessionFactory sqlSessionFactory;
  @Override
  public List<FilterConfig> findByStorageId(Integer storageId) {
    return filterConfigMapper.findByStorageId(storageId);
  }

  @Override
  public int deleteByStorageId(Integer storageId) {
    int deleteSize = filterConfigMapper.deleteByStorageId(storageId);
    log.info("删除存储源 ID 为 {} 的过滤规则 {} 条", storageId, deleteSize);
    return deleteSize;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void batchSave(Integer storageId, List<FilterConfig> filterConfigList) {
    this.deleteByStorageId(storageId);
    log.info("更新存储源 ID 为 {} 的过滤规则 {} 条", storageId, filterConfigList.size());

    // 开启批量处理模式BATCH, 关闭自动提交事务的机制,改成全部数据一次性提交,更新完毕后再关闭sqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
    long startTime = System.currentTimeMillis();
    for (FilterConfig filterConfig : filterConfigList) {
      filterConfig.setStorageId(storageId);
      filterConfigMapper.insertSingle(filterConfig);

      if (log.isDebugEnabled()) {
        log.debug("新增过滤规则, 存储源 ID: {}, 表达式: {}, 描述: {}, 隐藏模式: {}",
            filterConfig.getStorageId(), filterConfig.getExpression(),
            filterConfig.getDescription(), filterConfig.getMode().getValue());
      }
    }
    // 一次性提交事务
    sqlSession.commit();
    sqlSession.close();
    long endTime = System.currentTimeMillis();
    log.info("总耗时:" + (endTime - startTime)  + "豪秒");
  }

  @Override
  public boolean checkFileIsHidden(Integer storageId, String fileName) {
    List<FilterConfig> filterConfigList = this.findByStorageId(storageId);
    return this.testPattern(storageId, filterConfigList, fileName);
  }

  @Override
  public boolean checkFileIsInaccessible(Integer storageId, String path) {
    List<FilterConfig> filterConfigList = this.findByStorageIdAndInaccessible(storageId);
    return this.testPattern(storageId, filterConfigList, path);
  }

  @Override
  public List<FilterConfig> findByStorageIdAndInaccessible(Integer storageId) {
    return filterConfigMapper.findByStorageIdAndInaccessible(storageId);
  }

  /**
   * 根据规则表达式和测试字符串进行匹配，如测试字符串和其中一个规则匹配上，则返回 true，反之返回 false。
   *
   * @param   patternList
   *          规则列表
   *
   * @param   test
   *
   *          测试字符串
   *
   * @return  是否显示
   */
  private boolean testPattern(Integer storageId, List<FilterConfig> patternList, String test) {
    // 如果规则列表为空, 则表示不需要过滤, 直接返回 false
    if (CollUtil.isEmpty(patternList)) {
      if (log.isDebugEnabled()) {
        log.debug("过滤规则列表为空, 存储源 ID: {}, 测试字符串: {}", storageId, test);
      }
      return false;
    }

    // 校验表达式
    for (FilterConfig filterConfig : patternList) {
      String expression = filterConfig.getExpression();

      if (StrUtil.isEmpty(expression)) {
        if (log.isDebugEnabled()) {
          log.debug("存储源 {} 过滤文件测试表达式: {}, 测试字符串: {}, 表达式为空，跳过该规则校验", storageId, expression, test);
        }
        continue;
      }

      try {
        boolean match = PatternMatcherUtils.testCompatibilityGlobPattern(expression, test);

        if (log.isDebugEnabled()) {
          log.debug("存储源 {} 过滤文件测试表达式: {}, 测试字符串: {}, 匹配结果: {}", storageId, expression, test, match);
        }

        if (match) {
          return true;
        }
      } catch (Exception e) {
        log.error("存储源 {} 过滤文件测试表达式: {}, 测试字符串: {}, 匹配异常，跳过该规则.", storageId, expression, test, e);
      }
    }

    return false;
  }
}
